package com.inspinia.base.util;

import com.inspinia.base.common.model.BaseConstants;
import org.apache.commons.codec.Charsets;
import org.apache.http.*;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.PrintWriter;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by WangJun on 16/5/6.
 */
public class HttpClientRequestUtil {

    /**
     * 创建HTTP连接池.
     */
    @Bean
    public PoolingHttpClientConnectionManager getConnectionManager() {
        ConnectionSocketFactory connectionSocketFactory = PlainConnectionSocketFactory
                .getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory>create()
                .register("http", connectionSocketFactory).build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
                registry);
        //最大连接数
        connectionManager.setMaxTotal(100);
        //设置每个路由的基础连接
        connectionManager.setDefaultMaxPerRoute(10);

        return connectionManager;
    }

    /**
     * 链接异常操作.
     */
    @Bean
    public HttpRequestRetryHandler getHttpRequestRetryHandler() {
        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception,
                                        int executionCount, HttpContext context) {
                if (executionCount >= 5) {// 如果已经重试了5次，就放弃
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超时
                    return false;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    return false;
                }
                if (exception instanceof SSLException) {// ssl握手异常
                    return false;
                }

                HttpClientContext clientContext = HttpClientContext
                        .adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果请求是幂等的，就再次尝试
                return !(request instanceof HttpEntityEnclosingRequest);
            }
        };
        return httpRequestRetryHandler;
    }

    /**
     * HTTP请求超时设置.
     */
    @Bean
    public RequestConfig getRequestConfig() {
        return RequestConfig
                .custom()
                .setSocketTimeout(2000)// 传输超时
                .setConnectTimeout(2000)// 连接超时
                .build();
    }

    protected Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    protected PoolingHttpClientConnectionManager connectionManager;
    @Autowired
    protected HttpRequestRetryHandler httpRequestRetryHandler;
    @Autowired
    protected RequestConfig requestConfig;
    //编码格式
    public static final String ENCODE_UTF8 = "UTF-8";

    /**
     * http请求基础类
     *
     * @param url     请求路径
     * @param json    请求数据json
     * @return
     * @throws IOException
     */
    public String post(String url, String json,String key) throws IOException {
        logger.info("Http Request Data:" + json);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setRetryHandler(httpRequestRetryHandler).build();

        HttpPost post = new HttpPost(url);
        post.setConfig(requestConfig);
        post.setHeader("key",key);

        StringEntity requestEntity = new StringEntity(json,
                Charset.forName(BaseConstants.URF8));
        requestEntity.setContentEncoding(BaseConstants.URF8);

        requestEntity.setContentType(ContentType.APPLICATION_JSON.getMimeType());
        post.setEntity(requestEntity);

        HttpResponse response = httpClient.execute(post);
        HttpEntity responseEntity = response.getEntity();
        Header[] allHeaders = response.getAllHeaders();
        if (response.getStatusLine().getStatusCode() != 200) {
            logger.error("HttpClientRequestUtil Response Error,Status Code = {}", response
                    .getStatusLine().getStatusCode());
            for (Header header : allHeaders) {
                logger.error("HttpClientRequestUtil Response Error,Header Info = {}", header);
            }
            post.abort();
            return null;
        }
        String responseJson = EntityUtils.toString(responseEntity, Charsets.UTF_8);
        logger.info("Http Response Data:" + responseJson);
        return responseJson;
    }

    public static void responseMessage(String json, HttpServletResponse httpServletResponse) {
        httpServletResponse.setCharacterEncoding(BaseConstants.URF8); //设置编码格式
        httpServletResponse.setContentType("application/json");   //设置数据格式
        PrintWriter out = null;
        try {
            out = httpServletResponse.getWriter();
            out.print(json);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            out.flush();
            out.close();
        }
    }

    /**
     * HTTP Get 获取内容
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @return 页面内容
     */
    public  String get(String url, Map<String, String> params) {
        if(StringUtils.isBlank(url)){
            return "";
        }
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setRetryHandler(httpRequestRetryHandler).build();
        try {
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                for (String key : params.keySet()) {
                    pairs.add(new BasicNameValuePair(key, params.get(key)));
                }
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, Charsets.UTF_8));
                if (!url.contains("http://")){
                    url = "http://"+ url;
                }
            }
            HttpGet httpGet = new HttpGet(url.replace(" ",""));
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}